package net 
{
	import com.google.protobuf.Closure;
	import com.google.protobuf.MessageLite;
	import com.google.protobuf.MethodDescriptor;
	import com.google.protobuf.RpcChannel;
	import com.google.protobuf.RpcController;
	import com.google.protobuf.Service;
	import com.google.protobuf.ServiceDescriptor;
	
	import flash.events.*;
	import flash.net.*;
	import flash.utils.*;
	
	import org.osmf.media.MediaElement;
	
	import rpc.*;
	import rpc.msg.Account;
	import rpc.msg.None;
	import rpc.msg.Ping;
	
	/**
	 * ...
	 * @author hotlala
	 */
	public class Net extends SCProtocol_Service implements RpcChannel
	{	
		static private var _instance:Net = null;
		
		private var _callback:Function = null;
		
		private var _socket			:Socket = new Socket(); 
		private var _host			:String = "127.0.0.1";
		private var _port			:uint = 60001;
		private var _speed			:int = 1;
		
		private var _ping_timer		:Timer = new Timer(5000);
		private var _flush_timer	:Timer = new Timer(1000);
		private var _recv_buffer	:ByteArray = new ByteArray();
		private var _send_buffer	:ByteArray = new ByteArray();
		
		private var _stub 	:CSProtocol_Stub ;
		public function Net(helper:Creater) 
		{
			//_socket.endian = Endian.LITTLE_ENDIAN;
			_socket.addEventListener(SecurityErrorEvent.SECURITY_ERROR , _error);
			_socket.addEventListener(IOErrorEvent.IO_ERROR , _error);
			_socket.addEventListener(ProgressEvent.SOCKET_DATA, _recv);
			_socket.addEventListener(Event.CLOSE, _close);
			_socket.addEventListener(Event.CONNECT, _connected);
			
			_flush_timer.addEventListener(TimerEvent.TIMER, _flush);
			_ping_timer.addEventListener(TimerEvent.TIMER, _ping);
			
			
			_stub = new CSProtocol_Stub(this);
		}
		
		private var _output:ByteArray = new ByteArray;
		override public function callMethod(method:MethodDescriptor, controller:RpcController, request:MessageLite,response:MessageLite,done:Closure):void
		{
				_output.clear();
				request.writeToDataOutput(_output);
				var head :ByteArray = new ByteArray;
				head.endian = Endian.LITTLE_ENDIAN;
				head.writeShort(124);
				head.writeShort(_output.length);
				head.writeShort(method.service.index);
				head.writeShort(method.index);
				head.endian = Endian.BIG_ENDIAN;
				head.position = 0;
				_socket.writeBytes(head);
				_socket.writeBytes(_output);
				//trace ( _socket.bytesPending);
				_socket.flush();
		}
		
		public function get stub():CSProtocol_Stub
		{
				return _stub;
		}
		
		public function get speed():int
		{
			return _speed;
		}

		public function set speed(value:int):void
		{
			_speed = value;
			_reset();
		}

		public function get port():uint
		{
			return _port;
		}

		public function set port(value:uint):void
		{
			_port = value;
		}

		public function get host():String
		{
			return _host;
		}

		public function set host(value:String):void
		{
			_host = value;
		}

		static public function instance():Net
		{
			if (null == _instance)
			{
				_instance = new Net( new Creater() );
			}
			
			return _instance;
		}
		
		public function init(callback:Function = null):void
		{
			//_callback = callback;
			_socket.connect(host, port);
			_reset();
			//todo
			//_callback.apply();
		}
		
		private function _reset():void
		{
			_flush_timer.reset()
			_flush_timer.delay = _speed * 1000;
			_flush_timer.start();
		}
		
		private function _error(evt:Event):void
		{
			trace( evt );
		}
		
		private function _close(evt:Event=null):void
		{
			trace( evt );
		}
		
		private function _connected(evt:Event):void
		{
			_ping_timer.start();			
			
			
			//_socket.flush();
		}
		
		private function _recv(evt:ProgressEvent):void
		{
			if(evt.bytesTotal!=evt.bytesLoaded)
			{
				trace(evt.bytesTotal,"--",evt.bytesLoaded);
			}
			
			var bytes :ByteArray = new ByteArray;
			bytes.endian = Endian.BIG_ENDIAN;
			_socket.readBytes(bytes,0,4);
			bytes.position = 0;
			bytes.endian = Endian.LITTLE_ENDIAN;
			var s :int = bytes.readShort(); 
			var m :int = bytes.readShort();
			
			var method:MethodDescriptor = this.getMethodByIndex(m);
			var request :MessageLite = this.getRequestPrototype(method);
			
			request.readFromDataOutput(_socket);
			
			super.callMethod(method,null,request,null,null);
			
			
		}
		
		private function _flush(evt:Event):void
		{
			if(_socket.connected /*&& _socket.bytesPending*/)
			{
//				var acc:Account = new Account;
//				acc.name = "123456"
//				stub.login(null,acc,null,null);
				
				
			//	trace("socket flush");
			}
		}
		
		///////////////////////////////////////////////////////////////////////////////////////////////
		public function _ping(evt:Event):void
		{
			var p:None = new None;
			p.value = getTimer();
			stub.ping(null,p,null,null);
			
		}
		
		override public function pong(controller:RpcController,request:None,response:None,done:Closure) : void 
		{
			trace ( request.value );
		}
	}

}


class Creater { };